package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.utils.*;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.domain.vo.LearningStatusVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author User
 * @description 针对表【learning_lesson(学生课表)】的数据库操作Service实现
 * @createDate 2024-12-07 11:29:36
 */
@Service
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {

	@Autowired
	private CourseClient courseClient;

	@Autowired
	private CatalogueClient catalogueClient;

	@Autowired
	private LearningRecordMapper recordMapper;

	/**
	 * 添加课程到课表
	 *
	 * @param userId
	 * @param courseIds
	 */
	@Override
	public void addUserLessons(Long userId, List<Long> courseIds) {
		//2.获取所有的课程信息
		List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(courseIds);
		//2.判断是否有课程信息
		if (simpleInfoList.isEmpty()) {
			log.error("课程信息不存在,无法添加到课表");
			return;
		}
		//3.遍历课程信息，添加到课表中
		List<LearningLesson> list = new ArrayList<>(simpleInfoList.size());
		for (CourseSimpleInfoDTO info : simpleInfoList) {
			LearningLesson lesson = new LearningLesson();
			//3.1 获取过期时间

//			LocalDateTime now = LocalDateTime.now();
//			lesson.setCreateTime(now);
//			lesson.setExpireTime(info.getPurchaseEndTime());

			Integer validDuration = info.getValidDuration();
			if (validDuration != null && validDuration > 0) {
				LocalDateTime now = LocalDateTime.now();
				lesson.setCreateTime(now);
				lesson.setExpireTime(now.plusMonths(validDuration));
			}

			lesson.setCourseId(info.getId());
			lesson.setUserId(userId);
			list.add(lesson);
		}
		//4.批量添加
		saveBatch(list);
	}

	/**
	 * 分页查询我的课表
	 *
	 * @param pageQuery
	 * @return
	 */
	@Override
	public PageDTO<LearningLessonVO> queryMyLessons(PageQuery pageQuery) {
		//1.获取当前登录用户
		Long userId = UserContext.getUser();
		//2.分页查询
		Page page = new Page(pageQuery.getPageNo(), pageQuery.getPageSize());
		LambdaQueryWrapper<LearningLesson> wrapper = Wrappers.<LearningLesson>lambdaQuery()
				.eq(LearningLesson::getUserId, userId)
				.orderBy(true, pageQuery.getIsAsc(), LearningLesson::getLatestLearnTime, null);
		page(page, wrapper);
		List<LearningLesson> records = page.getRecords();
		if (records.isEmpty()) {
			return PageDTO.empty(page);
		}
		//获取所有的课程id集合
		List<Long> collect = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toList());
		//远程调用查到所有的课程集合
		List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(collect);
		if (CollUtils.isEmpty(simpleInfoList)) {
			// 课程不存在，无法添加
			throw new BadRequestException("课程信息不存在！");
		}
		//将课程集合转换为map，key为课程id，value为课程信息
		Map<Long, CourseSimpleInfoDTO> map = simpleInfoList.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, info -> info));
		//3.封装课程信息
		List<LearningLessonVO> list = new ArrayList<>();
		for (LearningLesson record : records) {
			LearningLessonVO learningLessonVO = BeanUtils.copyBean(record, LearningLessonVO.class);
//			List<Long> ids = new ArrayList<>();
//			ids.add(record.getCourseId());
//			List<CourseSimpleInfoDTO> simpleInfoList = courseClient.getSimpleInfoList(ids);
//			CourseSimpleInfoDTO courseInfoById = simpleInfoList.get(0);
			CourseSimpleInfoDTO courseSimpleInfoDTO = map.get(record.getCourseId());
			learningLessonVO.setCourseName(courseSimpleInfoDTO.getName());
			learningLessonVO.setCourseCoverUrl(courseSimpleInfoDTO.getCoverUrl());
			learningLessonVO.setSections(courseSimpleInfoDTO.getSectionNum());
			list.add(learningLessonVO);
		}
		return PageDTO.of(page, list);
	}

	/**
	 * 查询当前正在学习的课程
	 *
	 * @return
	 */
	@Override
	public LearningLessonVO queryMyCurrentLesson() {
		//1.获取当前用户
		Long userId = UserContext.getUser();
		//2.查询当前正在学习的课程
		LearningLesson lesson = lambdaQuery()
				.eq(LearningLesson::getUserId, userId)
				.eq(LearningLesson::getPlanStatus, LessonStatus.LEARNING.getValue())
				.orderByDesc(LearningLesson::getLatestLearnTime)
				.last("limit 1")
				.one();
		//3.查询课程信息
		if (lesson == null) {
			return null;
		}
		//4.构造返回值
		LearningLessonVO vo = BeanUtils.copyBean(lesson, LearningLessonVO.class);
		CourseFullInfoDTO courseInfoById = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
		if (courseInfoById != null) {
			vo.setCourseName(courseInfoById.getName());
			vo.setCourseCoverUrl(courseInfoById.getCoverUrl());
			vo.setSections(courseInfoById.getSectionNum());
		}
		//5.查询课表中的课程数量
		Integer count = lambdaQuery().eq(LearningLesson::getUserId, userId)
				.count();
		vo.setCourseAmount(count);
		//6.查询课程小节信息
		List<CataSimpleInfoDTO> cataInfos =
				catalogueClient.batchQueryCatalogue(CollUtils.singletonList(lesson.getLatestSectionId()));
		if (!CollUtils.isEmpty(cataInfos)) {
			CataSimpleInfoDTO cataInfo = cataInfos.get(0);
			vo.setLatestSectionName(cataInfo.getName());
			vo.setLatestSectionIndex(cataInfo.getCIndex());
		}
		return vo;
	}

	/**
	 * 删除已经失效的课程
	 *
	 * @param courseId
	 */
	@Override
	public void removeByCId(Long courseId) {
		//1.获取当前用户的id
		Long userId = UserContext.getUser();
		//2.查询要删除的课程
		LearningLesson lesson = lambdaQuery()
				.eq(LearningLesson::getUserId, userId)
				.eq(LearningLesson::getCourseId, courseId)
				.one();
		if (lesson == null) {
			throw new BadRequestException("课程不存在");
		}
		//3.判断课程状态
		if (!lesson.getStatus().equals(LessonStatus.EXPIRED.getValue())) {
			throw new BadRequestException("课程未失效,不能删除");
		}
		//3.删除课程
		boolean result = removeById(lesson.getId());
		if (!result) {
			throw new BadRequestException("删除课程失败");
		}
	}

	/**
	 * 校验当前用户是否可以学习当前课程
	 *
	 * @param courseId 课程id
	 * @return lessonId，如果是报名了则返回lessonId，否则返回空
	 */
	@Override
	public Long isLessonValid(Long courseId) {
		Long userId = UserContext.getUser();
		//1.查询当前用户是否已经购买过该课程
		LearningLesson lesson = lambdaQuery()
				.eq(LearningLesson::getUserId, userId)
				.eq(LearningLesson::getCourseId, courseId)
				.one();
		if (lesson == null) {
			return null;
		}
		if (lesson.getStatus().equals(LessonStatus.EXPIRED.getValue())) {
			return null;
		}
		return lesson.getId();
	}

	/**
	 * 检查课程状态
	 *
	 * @param courseId
	 * @return
	 */
	@Override
	public LearningStatusVO queryLearningStatus(Long courseId) {
		Long userId = UserContext.getUser();
		LearningLesson lesson = lambdaQuery()
				.eq(LearningLesson::getUserId, userId)
				.eq(LearningLesson::getCourseId, courseId)
				.one();
		if (lesson != null) {
			LearningStatusVO vo = BeanUtils.copyBean(lesson, LearningStatusVO.class);
			vo.setId(lesson.getId());
			return vo;
		}
		return null;
	}

	/**
	 * 统计课程学习人数
	 *
	 * @param courseId 课程id
	 * @return 学习人数
	 */
	@Override
	public Integer countLearningLessonByCourse(Long courseId) {
		return lambdaQuery()
				.eq(LearningLesson::getCourseId, courseId)
				.count();
	}

	/**
	 * 查询用户的课表信息
	 *
	 * @param userId
	 * @param courseId
	 * @return
	 */
	@Override
	public LearningLesson queryByUserAndCourseId(Long userId, Long courseId) {
		LambdaQueryWrapper<LearningLesson> queryWrapper = new QueryWrapper<LearningLesson>()
				.lambda()
				.eq(LearningLesson::getUserId, userId)
				.eq(LearningLesson::getCourseId, courseId);
		return getOne(queryWrapper, false);
	}

	/**
	 * 创建学习计划
	 *
	 * @param courseId
	 * @param freq
	 */
	@Override
	public void createLearningPlan(Long courseId, Integer freq) {
		// 1.获取当前登录的用户
		Long userId = UserContext.getUser();
		// 2.查询课表中的指定课程有关的数据
		LearningLesson lesson = queryByUserAndCourseId(userId, courseId);
		AssertUtils.isNotNull(lesson, "课程信息不存在！");
		// 3.修改数据
		LearningLesson l = new LearningLesson();
		l.setId(lesson.getId());
		l.setWeekFreq(freq);
		if (lesson.getPlanStatus() == PlanStatus.NO_PLAN) {
			l.setPlanStatus(PlanStatus.PLAN_RUNNING);
		}
		boolean result = updateById(l);
		if (!result) {
			throw new BadRequestException("创建学习计划失败");
		}
	}

	/**
	 * 查询我的学习计划
	 *
	 * @param query
	 * @return
	 */
	@Override
	public LearningPlanPageVO queryMyPlans(PageQuery query) {
		LearningPlanPageVO result = new LearningPlanPageVO();
		// 1.获取当前登录用户
		Long userId = UserContext.getUser();
		// 2.获取本周起始时间
		LocalDate now = LocalDate.now();
		LocalDateTime begin = DateUtils.getWeekBeginTime(now);
		LocalDateTime end = DateUtils.getWeekEndTime(now);
		// 3.查询本周计划学习的所有课程，满足三个条件：属于当前用户、有学习计划、学习中
		List<LearningLesson> lessons = lambdaQuery()
				.eq(LearningLesson::getUserId, userId)
				.eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING)
				.in(LearningLesson::getStatus, LessonStatus.NOT_BEGIN, LessonStatus.LEARNING)
				.list();
		if (CollUtils.isEmpty(lessons)) {
			return null;
		}
		// 4.统计当前用户每个课程的已学习小节数量
		List<LearningRecord> learnedRecords = recordMapper.selectList(new QueryWrapper<LearningRecord>().lambda()
				.eq(LearningRecord::getUserId, userId)
				.eq(LearningRecord::getFinished, true)
				.gt(LearningRecord::getFinishTime, begin)
				.lt(LearningRecord::getFinishTime, end)
		);
		Map<Long, Long> countMap = learnedRecords.stream()
				.collect(Collectors.groupingBy(LearningRecord::getLessonId, Collectors.counting()));

		// 5.查询总的统计数据
		// 5.1.本周总的已学习小节数量
		int weekFinished = learnedRecords.size();
		result.setWeekFinished(weekFinished);
		// 5.2.本周总的计划学习小节数量
		int weekTotalPlan = lessons.stream().mapToInt(LearningLesson::getWeekFreq).sum();
		result.setWeekTotalPlan(weekTotalPlan);
		// TODO 5.3.本周学习积分

		// 6.处理分页数据
		// 6.1.分页查询课表信息以及学习计划信息
		Page<LearningLesson> p = new Page<>(query.getPageNo(), query.getPageSize(), lessons.size());
		List<LearningLesson> records = CollUtils.sub(lessons, query.from(), query.from() + query.getPageSize());
		if (CollUtils.isEmpty(records)) {
			return result;
		}
		// 6.2.查询课表对应的课程信息
		Map<Long, CourseSimpleInfoDTO> cMap = queryCourseSimpleInfoList(records);
		// 6.3.组装数据VO
		List<LearningPlanVO> voList = new ArrayList<>(records.size());
		for (LearningLesson r : records) {
			// 6.4.1.拷贝基础属性到vo
			LearningPlanVO vo = BeanUtils.copyBean(r, LearningPlanVO.class);
			// 6.4.2.填充课程详细信息
			CourseSimpleInfoDTO cInfo = cMap.get(r.getCourseId());
			if (cInfo != null) {
				vo.setCourseName(cInfo.getName());
				vo.setSections(cInfo.getSectionNum());
			}
			// 6.4.3.每个课程的本周已学习小节数量
			vo.setWeekLearnedSections(countMap.getOrDefault(r.getId(), 0L).intValue());
			voList.add(vo);
		}
		return result.pageInfo(p.getTotal(), p.getPages(), voList);
	}

	/**
	 * 根据课程id查询课程详细信息
	 * @param records
	 * @return
	 */
	private Map<Long, CourseSimpleInfoDTO> queryCourseSimpleInfoList(List<LearningLesson> records) {
		// 3.1.获取课程id
		Set<Long> cIds = records.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());
		// 3.2.查询课程信息
		List<CourseSimpleInfoDTO> cInfoList = courseClient.getSimpleInfoList(cIds);
		if (CollUtils.isEmpty(cInfoList)) {
			// 课程不存在，无法添加
			throw new BadRequestException("课程信息不存在！");
		}
		// 3.3.把课程集合处理成Map，key是courseId，值是course本身
		Map<Long, CourseSimpleInfoDTO> cMap = cInfoList.stream()
				.collect(Collectors.toMap(CourseSimpleInfoDTO::getId, c -> c));
		return cMap;
	}
}




